#include <cpp-pinyin/G2pglobal.h>
#include <QStringList>
#include <common/pinyinconverter.h>
#include <filesystem>
#include "pinyinconverter_p.h"
PinyinConverterPrivate::PinyinConverterPrivate(PinyinConverter* p)
	: p(p)
{
	init();
}
PinyinConverterPrivate::~PinyinConverterPrivate() = default;

QString PinyinConverterPrivate::cvt2Pinyin(const QString& str) const
{
	const auto list = m_pyPtr->hanziToPinyin(str.toStdString(),
											 Pinyin::ManTone::NORMAL,
											 Pinyin::Error::Default,
											 false,
											 false,
											 true);
	return QString::fromStdString(list.toStdStr());
}

QStringList PinyinConverterPrivate::cvt2PinyinList(const QString& str)
{
	const auto res = m_pyPtr->hanziToPinyin(str.toStdString(),
											 Pinyin::ManTone::NORMAL,
											 Pinyin::Error::Default,
											 true,
											 false,
											 true);
	std::vector<std::vector<std::string>> options;
	for (const auto &entry : res) {
		std::vector<std::string> opts;

		if (entry.candidates.size() > 0)
		{
			for (const auto &p : entry.candidates) {
				opts.push_back(p);
			}
		}
		else
		{
			opts.push_back(entry.pinyin);
		}
		if (!opts.empty())
			options.push_back(std::move(opts));
	}
	// 笛卡尔积
	QStringList result;
	for (const auto &s : cartesianProduct(options)) {
		result << QString::fromStdString(s);
	}
	return result;
}
QString PinyinConverterPrivate::cvt2FirstCell(const QString& str) const
{
	const auto list = m_pyPtr->hanziToPinyin(str.toStdString(),
										 Pinyin::ManTone::NORMAL,
										 Pinyin::Error::Default,
										 false,
										 false,
										 true);
	QString res;
	for (const auto& item: list)
	{
		auto pinyin = item.pinyin;
		std::string cell;
		if (pinyin.length() > 0)
		{
			cell = pinyin.at(0);
		}
		res.append(QString::fromStdString(cell));
	}
	return res;
}

void PinyinConverterPrivate::init()
{
	const auto appPath = std::filesystem::current_path() / "dict";
	Pinyin::setDictionaryPath(appPath);
	m_pyPtr = std::make_unique<Pinyin::Pinyin>();
}
std::vector<std::string> PinyinConverterPrivate::cartesianProduct(const std::vector<std::vector<std::string>>& options)
{
	std::vector<std::string> result;
	if (options.empty())
		return result;
	std::string current;
	cartesianRecursive(options, 0, current, result);
	return result;
}

void PinyinConverterPrivate::cartesianRecursive(const std::vector<std::vector<std::string>> &options,
						int depth,
						std::string &current,
						std::vector<std::string> &result)
{
	if (depth == options.size()) {
		result.push_back(current);
		return;
	}
	for (const auto &p : options[depth]) {
		current += p;
		cartesianRecursive(options, depth + 1, current, result);
		current.resize(current.size() - p.size()); // 回溯
	}
}